昨天群里同学提到了一个问题。
为啥不要写for/foreach,为啥要引入高阶函数这些个东西。我现在的理解就是引入这些东西,就是为了用一种更加“声明式”的,更加“表意”的,而非“命令式”的方式来写代码。
以下是我的回答,有所删改:
从另外一个视角来看这个问题,高阶函数出现主要是能够把控制流作为数据来操作了。比如map等这些函数,实际上就是通过控制流简化了原本的程序结构,直接把循环结构给干掉了,只利用选择和递归就能解决所有问题。(实际上选择结构也可以被干掉,不过这样写出来的东西就更不说人话了。)
这种好处是就是你不用关注操作控制流后面具体实现,因为对应的表述方式没有太大的差别。比如使用循环结构来操作程序的时候,你是很难控制这段程序如何去并行执行的,虽然有openmp这样的指令系统。但也有额外的操作和开销。而如果是使用map,那就把后面对应换成并行的实现就好了,具体调用的代码并不需要做改变。比如Java的ParallelStream、Visual C++的Parallel Patterns Library。甚至微软后面推出的 C++ AMP,能够直接采用GPU来加速计算,仍然采用与STL/PPL一样的调用方式。
设计模式实际上一定程度在以各种形式组合出来这种高阶控制流,比如可以自由组合结构的Composite和可以层级解析结构的Interpreter,就等于变相把构建语法树和解析语法树这两个本来应该由编译器完成的操作让程序员自己来完成。
所以超出结构化编程以后的各种新的控制结构和控制流,多少都是基于“高阶函数”这样一个公共的基础,通过函数和值的捕获、传递和组合来实现诸如续延、协程、异步、响应式等等。主要的思路还没变,就是在简化前端(即程序员)操作的情况下更好的来利用操作系统和硬件的基础设施。
有些编程语言会选择把这些高阶控制流设计的更友好一些,把本来的高阶结构隐藏起来,在语法层把自己伪装成结构化编程的老样子,利用编译器的转换来实现。比如JavaScript的async/await,表面上看还是if/for/try/catch,实际编译过以后就变成Promise和Generator了。